#include "CLoggerImpl.h"
#include "CLoggerImpl_p.h"
#include <qtextedit.h>
#include <qdebug.h>
#include <string>

#include "spdlog/spdlog.h"
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/sinks/qt_sinks.h"
#include "spdlog/sinks/stdout_color_sinks.h"


#pragma execution_character_set("utf-8")

#define STRING_CONVERT(x) _STRING_CONVERT(x)
#define _STRING_CONVERT(x) #x
#define LOCATION __FUNCTION__ "("STRING_CONVERT(__LINE__)")"
#define WORDWARP "\r\n"

CLoggerImplPrivate::CLoggerImplPrivate(CLoggerImpl* parent)
	:q_ptr{parent}, m_type{ CLoggerImpl::LogType::LOG_FILE }
{}

CLoggerImplPrivate::~CLoggerImplPrivate()
{
}



CLoggerImpl::CLoggerImpl(QObject *parent)
	: QObject(parent), d_ptr{ new CLoggerImplPrivate(this) }
{
	Q_CHECK_PTR(d_ptr);
}

CLoggerImpl::~CLoggerImpl()
{
	if (d_ptr)
		delete d_ptr;
}

void CLoggerImpl::InitNormalLog(QStringView logger_name, QStringView file_name, const LogType type, unsigned int hour, unsigned int minute)
{
	if (d_ptr)
	{
		d_ptr->m_normal_logger = spdlog::daily_logger_mt(logger_name.toString().toStdString(), file_name.toString().toStdString(), hour, minute);
		Q_CHECK_PTR(d_ptr->m_normal_logger);
		if (!d_ptr->m_normal_logger)
		{
			qDebug() << LOCATION << " init failed!" << WORDWARP;
			return;
		}
		else
			d_ptr->m_type = type;
		d_ptr->m_normal_logger->set_level(spdlog::level::trace);
		d_ptr->m_normal_logger->flush_on(spdlog::level::trace);
		spdlog::set_level(spdlog::level::trace);
	}
}

void CLoggerImpl::InitQtLog(QStringView logger_name, QTextEdit* ptr, unsigned int maxlines)
{
	if (d_ptr && ptr)
	{
		d_ptr->m_qt_logger = spdlog::qt_color_logger_mt(logger_name.toString().toStdString(), ptr, maxlines);
		Q_CHECK_PTR(d_ptr->m_qt_logger);
		if (!d_ptr->m_qt_logger)
		{
			qDebug() << LOCATION << " init failed!" << WORDWARP;
			return;
		}
		d_ptr->m_qt_logger->set_level(spdlog::level::trace);
		d_ptr->m_qt_logger->flush_on(spdlog::level::trace);
	}
}

void CLoggerImpl::WriteDebugMsg(QStringView msg)
{
	switch (d_ptr->m_type)
	{
	case LogType::LOG_NONE:
		break;
	case LogType::LOG_FILE:
		d_ptr->m_normal_logger->debug(msg.toString().toStdString());
		break;
	case LogType::LOG_CONSOLE:
		spdlog::debug(msg.toString().toStdString());
		break;
	case LogType::LOG_NATIVE:
		qDebug() << msg;
		break;
	case LogType::LOG_ALL:
		d_ptr->m_normal_logger->debug(msg.toString().toStdString());
		spdlog::debug(msg.toString().toStdString());
		qDebug() << msg;
		break;
	default:
		spdlog::debug(msg.toString().toStdString());
		break;
	}
}

void CLoggerImpl::WriteLogByLevel(QStringView msg, const LogLevel level)
{
	switch (d_ptr->m_type)
	{
	case LogType::LOG_NONE:
		break;
	case LogType::LOG_FILE:
		WriteDefFile(msg, level);
		break;
	case LogType::LOG_CONSOLE:
		WriteDefConsole(msg,level);
		break;
	case LogType::LOG_NATIVE:
		WriteDefNative(msg, level);
		break;
	case LogType::LOG_ALL:
		WriteDefFile(msg, level);
		WriteDefNative(msg, level);
		WriteDefConsole(msg, level);
		break;
	default:
		break;
	}
}

void CLoggerImpl::WriteQtLog(QStringView msg, const LogLevel level)
{
	switch (level)
	{
	case LogLevel::LOG_TRACE:
		d_ptr->m_qt_logger->trace(msg.toString().toStdString());
		break;
	case LogLevel::LOG_DEBUG:
		d_ptr->m_qt_logger->debug(msg.toString().toStdString());
		break;
	case LogLevel::LOG_INFO:
		d_ptr->m_qt_logger->info(msg.toString().toStdString());
		break;
	case LogLevel::LOG_WARN:
		d_ptr->m_qt_logger->warn(msg.toString().toStdString());
		break;
	case LogLevel::LOG_ERROR:
		d_ptr->m_qt_logger->error(msg.toString().toStdString());
		break;
	case LogLevel::LOG_CRITICAL:
		d_ptr->m_qt_logger->critical(msg.toString().toStdString());
		break;
	case LogLevel::LOG_OFF:
		break;
	default:
		d_ptr->m_qt_logger->debug(msg.toString().toStdString());
		break;
	}
}

void CLoggerImpl::WriteDefFile(QStringView msg, const LogLevel level)
{
	switch (level)
	{
	case LogLevel::LOG_TRACE:
		d_ptr->m_normal_logger->trace(msg.toString().toStdString());
		break;
	case LogLevel::LOG_DEBUG:
		d_ptr->m_normal_logger->debug(msg.toString().toStdString());
		break;
	case LogLevel::LOG_INFO:
		d_ptr->m_normal_logger->info(msg.toString().toStdString());
		break;
	case LogLevel::LOG_WARN:
		d_ptr->m_normal_logger->warn(msg.toString().toStdString());
		break;
	case LogLevel::LOG_ERROR:
		d_ptr->m_normal_logger->error(msg.toString().toStdString());
		break;
	case LogLevel::LOG_CRITICAL:
		d_ptr->m_normal_logger->critical(msg.toString().toStdString());
		break;
	case LogLevel::LOG_OFF:
		break;
	default:
		d_ptr->m_normal_logger->debug(msg.toString().toStdString());
		break;
	}
}

void CLoggerImpl::WriteDefConsole(QStringView msg, const LogLevel level)
{
	switch (level)
	{
	case LogLevel::LOG_TRACE:
		spdlog::trace(msg.toString().toStdString());
		break;
	case LogLevel::LOG_DEBUG:
		spdlog::debug(msg.toString().toStdString());
		break;
	case LogLevel::LOG_INFO:
		spdlog::info(msg.toString().toStdString());
		break;
	case LogLevel::LOG_WARN:
		spdlog::warn(msg.toString().toStdString());
		break;
	case LogLevel::LOG_ERROR:
		spdlog::error(msg.toString().toStdString());
		break;
	case LogLevel::LOG_CRITICAL:
		spdlog::critical(msg.toString().toStdString());
		break;
	case LogLevel::LOG_OFF:
		break;
	default:
		spdlog::debug(msg.toString().toStdString());
		break;
	}
}

void CLoggerImpl::WriteDefNative(QStringView msg, const LogLevel level)
{
	switch (level)
	{
	case LogLevel::LOG_TRACE:
		break;
	case LogLevel::LOG_DEBUG:
		qDebug() << msg;
		break;
	case LogLevel::LOG_INFO:
		qInfo() << msg;
		break;
	case LogLevel::LOG_WARN:
		qWarning() << msg;
		break;
	case LogLevel::LOG_ERROR:
		break;
	case LogLevel::LOG_CRITICAL:
		qCritical() << msg;
		break;
	case LogLevel::LOG_FATAL:
		qFatal(msg.toLocal8Bit());
		break;
	case LogLevel::LOG_OFF:
		break;
	default:
		break;
	}
}


